﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.Net;
using System.IO;
using System.Diagnostics;
using System.Security.Cryptography.X509Certificates;
using System.Net.Security;
using System.Security.Authentication;
using System.Runtime.InteropServices;
using System.Threading;
using System.Web;
using System.IO.Compression;
using System.Collections.Specialized;
using Jelly2013.Entity;
using Jelly2013.Query;

namespace Jelly2013
{
    public partial class Form_Main : Form
    {
        public static string _URL_Buy = "http://mgjwang.com/";

        #region 全局变量
        [DllImport("wininet.dll", CharSet = CharSet.Auto, SetLastError = true)]
        public static extern bool InternetSetCookie(string lpszUrlName, string lbszCookieName, string lpszCookieData);

        /// <summary>
        /// 无参数方法委托
        /// </summary>
        public delegate void doWorkDelegate();
        /// <summary>
        /// UI显示消息委托
        /// </summary>
        /// <param name="msg"></param>
        public delegate void showMsgDelegate1(string msg);
        /// <summary>
        /// 得到焦点委托
        /// </summary>
        /// <returns></returns>
        public delegate void focusDelegate1(Control control);
        /// <summary>
        /// 修改控件文字委托
        /// </summary>
        /// <param name="con"></param>
        /// <param name="text"></param>
        /// <param name="enable"></param>
        public delegate void setControlTextDelegate1(Control con, string text, bool enable);
        public delegate void setControlVisibleDelegate(Control con, bool flag);
        public doWorkDelegate LoggedDelegate;
        public doWorkDelegate activateDelegate;
        public showMsgDelegate1 showMsgDelegate;
        public setControlTextDelegate1 setControlTextDelegate;
        public focusDelegate1 focusDelegate;
        public setControlVisibleDelegate set_ControlVisibleDelegate;

        private static readonly string DefaultUserAgent = "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.2; Trident/4.0; .NET CLR 1.1.4322; .NET4.0C; .NET4.0E; .NET CLR 2.0.50727; .NET CLR 3.0.04506.648; .NET CLR 3.5.21022; .NET CLR 3.0.4506.2152; .NET CLR 3.5.30729)";
        private static readonly string DefaultAccept = "image/gif, image/jpeg, image/pjpeg, image/pjpeg, application/xaml+xml, application/x-ms-xbap, application/x-ms-application, application/vnd.ms-excel, application/vnd.ms-powerpoint, application/msword, */*";
        private static readonly string DefaultContentType = "text/html; charset=GBK";
        /// <summary>
        /// 取得的HTML
        /// </summary>
        string html;
        /// <summary>
        /// 已经登录,当后台线程登录成功后,设为真
        /// </summary>
        private static bool logged = false;
        /// <summary>
        /// 正在运行中
        /// </summary>
        private static bool running = false;
        /// <summary>
        /// 手工停止
        /// </summary>
        private static bool stop = false;
        /// <summary>
        /// 尝试次数
        /// </summary>
        private static int count = 0;
        /// <summary>
        /// 便即登录时间
        /// </summary>
        private static DateTime beginTime;
        /// <summary>
        /// 登录成功时间
        /// </summary>
        private static DateTime endTime;
        /// <summary>
        /// 登录用时
        /// </summary>
        private TimeSpan timeSpan;
        /// <summary>
        /// 登录用时字符串
        /// </summary>
        private string timeSpanStr;
        /// <summary>
        /// 用于显示的时间与实际阻塞时间相同
        /// </summary>
        public static List<SeatType> _SelectedList_SeatType = new List<SeatType>();
        public static List<Passenger> _SelectedList_Passengers = new List<Passenger>();
        List<TicketInfo> selectTickList = new List<TicketInfo>();
        private List<SeatType> getSeatTypies()
        {
            List<SeatType> result = new List<SeatType>();
            result.Add(SeatType.商务座);
            result.Add(SeatType.特等座);
            result.Add(SeatType.一等座);
            result.Add(SeatType.二等座);
            result.Add(SeatType.高级软卧);
            result.Add(SeatType.软卧);
            result.Add(SeatType.硬卧);
            result.Add(SeatType.软座);
            result.Add(SeatType.硬座);
            result.Add(SeatType.无座);
            return result;
        }
        #endregion
        #region Load/init
        /// <summary>
        /// 开源软件
        /// </summary>
        public Form_Main()
        {
            InitializeComponent();
            LoggedDelegate = new doWorkDelegate(openInWebBrowser);
            activateDelegate = new doWorkDelegate(Activate);
            showMsgDelegate = new showMsgDelegate1(showLogInfo);
            setControlTextDelegate = new setControlTextDelegate1(changeControlTxt);
            focusDelegate = new focusDelegate1(setControlFocus);
            set_ControlVisibleDelegate = new setControlVisibleDelegate(Set_ControlVisible);
            InitApplication();
            initTicketDataGrid();
        }
        /// <summary>
        /// 初始化应用程序
        /// </summary>
        private void InitApplication()
        {
            StationList.Init();
        }
        /// <summary>
        /// 加载
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void frmTicketsHelper_Load(object sender, EventArgs e)
        {
            UIInit();
        }

        private void UIInit()
        {
            Bind_Station(null);
            cboStartTime.SelectedIndex = 0;
            dateStartDate.Value = DateTime.Now.AddDays(19);
            Bind_SeatType(null);
            //ThreadPool.QueueUserWorkItem(new WaitCallback(getVerificationCode), null);
            getVerificationCode(null);
        }
        private void Bind_Passenger(object obj)
        {
            Passenger_Query.GetList(null);
            List<Passenger> list = Passenger_Query.List;
            foreach (Passenger item in list)
            {
                chbListPassenger.Items.Add(new ComboBoxItem(item, item.ToString()));
            }
            chbListPassenger.SelectedValueChanged += new EventHandler(chbListPassenger_SelectedValueChanged);
            chbListPassenger.SelectedIndexChanged += new EventHandler(chbListPassenger_SelectedIndexChanged);
        }

        void chbListPassenger_SelectedValueChanged(object sender, EventArgs e)
        {
            Upadte_SelectPassenger();
        }

        void chbListPassenger_SelectedIndexChanged(object sender, EventArgs e)
        {
            Upadte_SelectPassenger();
        }

        private void Upadte_SelectPassenger()
        {
            Passenger p = (chbListPassenger.SelectedItem as ComboBoxItem).Value as Passenger;
            if (chbListPassenger.GetItemChecked(chbListPassenger.SelectedIndex))
            {
                if (!_SelectedList_Passengers.Contains(p))
                {
                    if (_SelectedList_Passengers.Count == 5)
                    {
                        MessageBox.Show("12306规定，最多选择5名乘客！");
                        return;
                    }
                    _SelectedList_Passengers.Add(p);
                    string lbl = "已选乘客：";
                    foreach (Passenger item in _SelectedList_Passengers)
                    {
                        lbl += item.Name + ";";
                    }
                    showInfo(lbl);
                }
            }
            else
            {
                if (_SelectedList_Passengers.Contains(p))
                {
                    _SelectedList_Passengers.Remove(p);
                    string lbl = "已选乘客：";
                    foreach (Passenger item in _SelectedList_Passengers)
                    {
                        lbl += item.Name + ";";
                    }
                    showInfo(lbl);
                }
            }
        }
        private void Bind_SeatType(object obj)
        {
            List<SeatType> list = getSeatTypies();
            foreach (SeatType item in list)
            {
                chbListSeatType.Items.Add(new ComboBoxItem(item,item.ToString()));
            }
            chbListSeatType.SelectedValueChanged += new EventHandler(chbListSeatType_SelectedValueChanged);
            chbListSeatType.SelectedIndexChanged += new EventHandler(chbListSeatType_SelectedIndexChanged);
        }

        void chbListSeatType_SelectedValueChanged(object sender, EventArgs e)
        {
            Update_SelectSeat();
        }

        void chbListSeatType_SelectedIndexChanged(object sender, EventArgs e)
        {
            Update_SelectSeat();
        }

        private void Update_SelectSeat()
        {
            SeatType seatType = (SeatType)(chbListSeatType.SelectedItem as ComboBoxItem).Value;
            if (chbListSeatType.GetItemChecked(chbListSeatType.SelectedIndex))
            {
                if (_SelectedList_SeatType.Contains(seatType) == false)
                {
                    _SelectedList_SeatType.Add(seatType);
                }
            }
            else
            {
                if (_SelectedList_SeatType.Contains(seatType) == true)
                {
                    _SelectedList_SeatType.Remove(seatType);
                }
            }
            _NeedPrePaint = true;
            dgvTiketInfo.Refresh();
            string lbl = "座席优先级：";
            for (int i = 0; i < _SelectedList_SeatType.Count; i++)
            {
                lbl += (i + 1).ToString() + "." + _SelectedList_SeatType[i].ToString() + ";";
            }
            lblSeate.Text = lbl;
        }

        void checkbox_CheckedChanged(object sender, EventArgs e)
        {
            CheckBox checkBox = sender as CheckBox;
            SeatType seatType = (SeatType)checkBox.Tag;
            if (checkBox.Checked)
            {
                if (_SelectedList_SeatType.Contains(seatType) == false)
                {
                    _SelectedList_SeatType.Add(seatType);
                }
            }
            else
            {
                if (_SelectedList_SeatType.Contains(seatType) == true)
                {
                    _SelectedList_SeatType.Remove(seatType);
                }
            }
            _NeedPrePaint = true;
            dgvTiketInfo.Refresh();
        }
        private void Bind_Station(object obj)
        {
            cboFromStation.Items.Clear();
            cboToStation.Items.Clear();
            List<Station> temp1 = StationList.Stations1;
            List<Station> temp2 = StationList.Stations2;
            cboFromStation.DataSource = temp1;
            cboToStation.DataSource = temp2;
            cboFromStation.DisplayMember = "Name";
            cboToStation.DisplayMember = "Name";
            cboFromStation.ValueMember = "Code";
            cboToStation.ValueMember = "Code";
            cboFromStation.SelectedIndex = 0;
            cboToStation.SelectedIndex = 0;
        }
        #endregion
        #region 验证码
        /// <summary>
        /// 得到验证码 外部调用
        /// </summary>
        /// <param name="obj"></param>
        private void getVerificationCode(object obj)
        {
            beginTime = DateTime.Now;
            System.Net.ServicePointManager.CertificatePolicy = new MyPolicy();
            count = 0;
            picValidImg.Image = null;
            setVerificationCode();
        }

        /// <summary>
        /// 得到验证码 内部重复调用 直到得到验证码
        /// </summary>
        private void setVerificationCode()
        {
            this.Invoke(setControlTextDelegate, new object[] { btnLogin, "加载中", false });
            sleep();
            count++;
            string url = "https://dynamic.12306.cn/otsweb/";
            try
            {
                CommUitl.getString(url, CommData.cookieContainer);
                url = "https://dynamic.12306.cn/otsweb/passCodeAction.do?rand=sjrand";
                picValidImg.Image = CommUitl.getVerificationCode(url, CommData.cookieContainer, CommData.cookieCollection, "https://dynamic.12306.cn/otsweb/loginAction.do?method=init");
                this.Invoke(this.showMsgDelegate, "取得验证码成功!");
                try
                {
                    txtVerificationCode.Text = new FuckCaptcha.Service_Captcha().Get_CaptchaCode(picValidImg.Image as Bitmap);
                    this.Invoke(this.showMsgDelegate, "验证码识别成功！");
                }
                catch (Exception ex)
                {
                    if (count > 5)
                    {
                        this.Invoke(this.showMsgDelegate, "验证码识别失败，重新识别!");
                    }
                    else
                    {
                        setVerificationCode();
                    }
                }
                endTime = DateTime.Now;
                timeSpan = endTime.Subtract(beginTime);
            }
            catch (Exception ex)
            {
                this.Invoke(this.showMsgDelegate, "取得验证码失败:" + ex.Message);
                setVerificationCode();
            }
            this.Invoke(setControlTextDelegate, new object[] { btnLogin, "登录", true });
        }
        #endregion
        #region UI控制/非业务杂七杂八
        private void picLoginIE_Click(object sender, EventArgs e)
        {
            this.Invoke(LoggedDelegate);
        }
        private void Set_ControlVisible(Control con, bool flag)
        {
            con.Visible = flag;
        }
        private string getMessage(string webResult)
        {
            string result = string.Empty;
            string keyword = "var message = \"";
            int startInt = webResult.IndexOf(keyword, 0);
            if (startInt > -1)
            {
                startInt += keyword.Length; ;
                int endInt = webResult.IndexOf("\";", startInt);
                result = webResult.Substring(startInt, endInt - startInt);
            }
            return result;
        }
        /// <summary>
        /// 线程阻塞,重试间隔
        /// </summary>
        private void sleep()
        {
            if (count > 0)
            {
                this.Invoke(new showMsgDelegate1(showInfo), "休息" + (TryInterval / 1000).ToString() + "秒");
                Thread.Sleep(TryInterval);
            }
        }

        /// <summary>
        /// 时间间隔
        /// </summary>
        private int TryInterval
        {
            get
            {
                return Convert.ToInt32(numJiange.Value) * 1000;
            }
        }

        /// <summary>
        /// 得到时间间隔的中文字符串
        /// </summary>
        private string getTimeSpanString(TimeSpan timeSpan)
        {
            StringBuilder timeSpanStr = new StringBuilder();

            if (timeSpan.Days > 0)
            {
                timeSpanStr.Append(timeSpan.Days);
                timeSpanStr.Append("天");
            }
            if (timeSpan.Hours > 0)
            {
                timeSpanStr.Append(timeSpan.Hours);
                timeSpanStr.Append("小时");
            }
            if (timeSpan.Minutes > 0)
            {
                timeSpanStr.Append(timeSpan.Minutes);
                timeSpanStr.Append("分");
            }
            if (timeSpan.Seconds > 0)
            {
                timeSpanStr.Append(timeSpan.Seconds);
                timeSpanStr.Append("秒");
            }
            if (timeSpanStr.Length == 0)
            {
                timeSpanStr.Append(timeSpan.Milliseconds);
                timeSpanStr.Append("毫秒");
            }
            return timeSpanStr.ToString();
        }

        /// <summary>
        /// 显示信息
        /// </summary>
        /// <param name="message"></param>
        private void messageBoxShowInfo(string message)
        {
            //this.Invoke(this.showMsgDelegate, message);
            MessageBox.Show(message, "开源软件 温馨提示", MessageBoxButtons.OK, MessageBoxIcon.Information, MessageBoxDefaultButton.Button1);
        }

        /// <summary>
        /// 打开浏览器
        /// </summary>
        private void openInWebBrowser()
        {
            foreach (Cookie cookie in CommData.cookieContainer.GetCookies(new Uri("https://dynamic.12306.cn/otsweb/loginAction.do?method=login")))
            {
                InternetSetCookie(
                    "https://" + cookie.Domain.ToString(),
                    cookie.Name.ToString(),
                    cookie.Value.ToString() + ";expires=Sun,22-Feb-2099 00:00:00 GMT");
            }
            string url = "https://dynamic.12306.cn/otsweb/";
            System.Diagnostics.Process.Start("IExplore.exe", url);

        }

        /// <summary>
        /// 显示信息
        /// </summary>
        /// <param name="info"></param>
        private void showLogInfo(string info)
        {
            //info = "第" + count + "次尝试:" + info;
            showInfo(info);
        }

        /// <summary>
        /// 显示信息-加时间
        /// </summary>
        /// <param name="info"></param>
        private void showTimeInfo(string info)
        {
            info = DateTime.Now.ToString("HH:mm:ss ") + info;
            showInfo(info);
        }

        /// <summary>
        /// 显示信息
        /// </summary>
        /// <param name="info"></param>
        private void showInfo(string info)
        {
            if (lstMsg.Items.Count > 20)
            {
                lstMsg.Items.RemoveAt(20);
            }
            lstMsg.Items.Insert(0, info);
        }

        /// <summary>
        /// 改变控件文字
        /// </summary>
        /// <param name="con">控件</param>
        /// <param name="text">文本</param>
        /// <param name="enable">控件是否可用</param>
        private void changeControlTxt(Control con, string text, bool enable)
        {
            if (con != null && string.IsNullOrEmpty(text) == false)
            {
                con.Text = text;
                con.Enabled = enable;
            }
        }

        /// <summary>
        /// 使控件得到焦点
        /// </summary>
        /// <param name="control"></param>
        private void setControlFocus(Control control)
        {
            if (control != null)
            {
                control.Focus();
            }
        }

        /// <summary>
        /// 点击得到新的验证码
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void picValidImg_Click(object sender, EventArgs e)
        {
            ThreadPool.QueueUserWorkItem(new WaitCallback(getVerificationCode), null);
        }
        #endregion
        #region DataGridView
        private void initTicketDataGrid()
        {
            dgvTiketInfo.RowPrePaint += new DataGridViewRowPrePaintEventHandler(dgvTiketInfo_RowPrePaint);
            dgvTiketInfo.AutoGenerateColumns = false;
            dgvTiketInfo.AllowUserToAddRows = false;
            dgvTiketInfo.RowHeadersVisible = false;

            DataGridViewCheckBoxColumn dgvcbcSlected = new DataGridViewCheckBoxColumn();
            dgvcbcSlected.Name = "dgvcbcSlected";
            dgvcbcSlected.HeaderText = "选择 ";
            dgvcbcSlected.DataPropertyName = "Selected";
            dgvcbcSlected.AutoSizeMode = DataGridViewAutoSizeColumnMode.ColumnHeader;

            DataGridViewTextBoxColumn dgtbcTrainDate = new DataGridViewTextBoxColumn();
            dgtbcTrainDate.Name = "dgtbcTrainDate";
            dgtbcTrainDate.HeaderText = "列车日期";
            dgtbcTrainDate.DataPropertyName = "TrainDate";
            dgtbcTrainDate.AutoSizeMode = DataGridViewAutoSizeColumnMode.ColumnHeader;

            DataGridViewTextBoxColumn dgtbcTrainNo = new DataGridViewTextBoxColumn();
            dgtbcTrainNo.Name = "dgtbcTrainNo";
            dgtbcTrainNo.HeaderText = "车次";
            dgtbcTrainNo.DataPropertyName = "StationTrainCode";
            dgtbcTrainNo.AutoSizeMode = DataGridViewAutoSizeColumnMode.ColumnHeader;

            DataGridViewTextBoxColumn dgtbcDepartureStation = new DataGridViewTextBoxColumn();
            dgtbcDepartureStation.Name = "dgtbcDepartureStation";
            dgtbcDepartureStation.HeaderText = "发站";
            dgtbcDepartureStation.DataPropertyName = "DepartureStation";
            dgtbcDepartureStation.Width = 88;

            DataGridViewTextBoxColumn dgtbcDrivingTime = new DataGridViewTextBoxColumn();
            dgtbcDrivingTime.Name = "dgtbcDrivingTime";
            dgtbcDrivingTime.HeaderText = "开车时间";
            dgtbcDrivingTime.DataPropertyName = "DrivingTime";
            dgtbcDrivingTime.AutoSizeMode = DataGridViewAutoSizeColumnMode.ColumnHeader;

            DataGridViewTextBoxColumn dgtbcDestinationStation = new DataGridViewTextBoxColumn();
            dgtbcDestinationStation.Name = "dgtbcDestinationStation";
            dgtbcDestinationStation.HeaderText = "到站";
            dgtbcDestinationStation.DataPropertyName = "DestinationStation";
            dgtbcDestinationStation.Width = 88;

            DataGridViewTextBoxColumn dgtbcArrivalTime = new DataGridViewTextBoxColumn();
            dgtbcArrivalTime.Name = "dgtbcArrivalTime";
            dgtbcArrivalTime.HeaderText = "到达时间";
            dgtbcArrivalTime.DataPropertyName = "ArrivalTime";
            dgtbcArrivalTime.AutoSizeMode = DataGridViewAutoSizeColumnMode.ColumnHeader;

            DataGridViewTextBoxColumn dgtbcElapsedTime = new DataGridViewTextBoxColumn();
            dgtbcElapsedTime.Name = "dgtbcElapsedTime";
            dgtbcElapsedTime.HeaderText = "历时";
            dgtbcElapsedTime.DataPropertyName = "ElapsedTime";
            dgtbcElapsedTime.AutoSizeMode = DataGridViewAutoSizeColumnMode.ColumnHeader;

            dgvTiketInfo.Columns.AddRange(dgvcbcSlected, dgtbcTrainDate, dgtbcTrainNo, dgtbcDepartureStation, dgtbcDrivingTime, dgtbcDestinationStation, dgtbcArrivalTime, dgtbcElapsedTime);

            SeatType seatType;
            for (int i = 0; i < CommData.SeatTypeCount; i++)
            {
                seatType = (SeatType)i;
                DataGridViewTextBoxColumn dgtbcSeetInfo = new DataGridViewTextBoxColumn();
                dgvTiketInfo.Name = "dgtbcSeetInfo" + seatType;
                dgtbcSeetInfo.HeaderText = SeatTypeDescriptionHelper.Description[seatType];
                dgtbcSeetInfo.DataPropertyName = seatType.ToString();
                dgtbcSeetInfo.AutoSizeMode = DataGridViewAutoSizeColumnMode.ColumnHeader;
                dgvTiketInfo.Columns.Add(dgtbcSeetInfo);
            }

            setDgvReadOnly();
        }

        void setDgvReadOnly()
        {
            for (int i = 0; i < dgvTiketInfo.Columns.Count; i++)
            {
                if (i > 0)
                {
                    dgvTiketInfo.Columns[i].ReadOnly = true;
                    dgvTiketInfo.Columns[i].SortMode = DataGridViewColumnSortMode.Automatic;
                    dgvTiketInfo.Columns[i].HeaderCell.SortGlyphDirection = SortOrder.None;
                }
            }
        }
        bool _NeedPrePaint = false;
        void dgvTiketInfo_RowPrePaint(object sender, DataGridViewRowPrePaintEventArgs e)
        {
            if (!_NeedPrePaint)
            {
                return;
            }
            if (e.RowIndex < dgvTiketInfo.Rows.Count)
            {
                TicketInfo ticketInfo = (dgvTiketInfo.Rows[e.RowIndex].DataBoundItem as TicketInfo);
                if (ticketInfo != null && ticketInfo.IsAvailable_Seat(_SelectedList_SeatType.ToArray()) == true)
                {
                    dgvTiketInfo.Rows[e.RowIndex].DefaultCellStyle.BackColor = Color.White;
                    foreach (TicketInfo item in selectTickList)
                    {
                        if (item.Equals(ticketInfo))
                        {
                            dgvTiketInfo.Rows[e.RowIndex].DefaultCellStyle.BackColor = Color.LawnGreen;
                            break;
                        }
                    }
                }
                else
                {
                    foreach (TicketInfo item in selectTickList)
                    {
                        if (item.Equals(ticketInfo))
                        {
                            dgvTiketInfo.Rows[e.RowIndex].DefaultCellStyle.BackColor = Color.Red;
                            DataGridViewCell cell = dgvTiketInfo.Rows[e.RowIndex].Cells[0];
                            cell.Selected = true;
                            break;
                        }
                    }
                    if (!ticketInfo.IsAvailable)
                    {
                        dgvTiketInfo.Rows[e.RowIndex].DefaultCellStyle.BackColor = Color.Gray;
                    }
                }
            }
            if (e.RowIndex == dgvTiketInfo.Rows.Count-1)
            {
                _NeedPrePaint = false;
            }
        }
        private void dgvTiketInfo_CellValueChanged(object sender, DataGridViewCellEventArgs e)
        {
            if (e.ColumnIndex == 0)
            {
                if (selectTickList.Count == 20)
                {
                    showLogInfo("在“已选车次”中双击车次可进行删除。");
                    showLogInfo("最多只能选择20个车次进行刷票");
                    return;
                }
                DataGridViewCheckBoxCell chkSelect = dgvTiketInfo[0, e.RowIndex] as DataGridViewCheckBoxCell;
                TicketInfo selectTicket = dgvTiketInfo.Rows[e.RowIndex].DataBoundItem as TicketInfo;
                if ((bool)chkSelect.Value)
                {
                    if (selectTickList.Count<1)
                    {
                        selectTickList.Add(selectTicket);
                    }
                    bool has = false;
                    foreach (TicketInfo item in selectTickList)
                    {
                        if (item.Equals(selectTicket))
                        {
                            has = true;
                            break;
                        }
                    }
                    if (!has)
                    {
                        selectTickList.Add(selectTicket);
                    }
                }
                else
                {
                    foreach (TicketInfo item in selectTickList)
                    {
                        if (item.Equals(selectTicket))
                        {
                            selectTickList.Remove(selectTicket);
                            break;
                        }
                    }
                }
            }
            _NeedPrePaint = true;
            dgvTiketInfo.Refresh();
            Bind_SelectedTicket();
        }
        private void Bind_SelectedTicket()
        {
            lsbSelectedTicket.Items.Clear();
            foreach (TicketInfo item in selectTickList)
            {
                lsbSelectedTicket.Items.Add(new ComboBoxItem(item, item.ToString()));
            }
            lsbSelectedTicket.ValueMember = "Value";
            lsbSelectedTicket.DisplayMember = "Text";
        }
        private void dgvTiketInfo_CellDoubleClick(object sender, DataGridViewCellEventArgs e)
        {
            if (e.ColumnIndex == 0|| e.RowIndex < 0)
            {
                return;
            }
            TicketInfo ticketInfo = dgvTiketInfo.Rows[e.RowIndex].DataBoundItem as TicketInfo;
            if (!ticketInfo.IsAvailable)
            {
                showLogInfo("您双击选择的车次无票");
                return;
            }
            dgvTiketInfo.DataSource = new BindingList<TicketInfo>();
            Form_Order_Add f = new Form_Order_Add(ticketInfo, false);
            f.ShowDialog();
        }
        
        #endregion
        #region 查询

        /// <summary>
        /// 得到当前窗口的查询条件实体
        /// </summary>
        private QueryTicketParam QueryTicketParam
        {
            get
            {
                return new QueryTicketParam(dateStartDate.Value.ToString("yyyy-MM-dd"),
                cboFromStation.SelectedValue.ToString(),
                cboToStation.SelectedValue.ToString(),
                string.Empty,
                getTrainPassType(),
                HttpUtility.UrlEncode(getTrainClass()),
                cboStartTime.Text);
            }
        }
        /// <summary>
        /// 得到列车类型选项
        /// </summary>
        /// <returns></returns>
        private string getTrainClass()
        {
            string result = string.Empty;
            CheckBox chk;
            foreach (Control item in pnlTrainType.Controls)
            {
                if (item is CheckBox)
                {
                    chk = item as CheckBox;
                    if (chk.Checked == true)
                    {
                        result += chk.Tag + "#";
                    }
                }
            }
            return result;
        }
        /// <summary>
        /// 得到列车始发/经过选项
        /// </summary>
        /// <returns></returns>
        private string getTrainPassType()
        {
            string result = string.Empty;
            RadioButton rdb;
            foreach (Control item in gobSearch.Controls)
            {
                if (item is RadioButton)
                {
                    rdb = item as RadioButton;
                    if (rdb.Checked)
                    {
                        result = rdb.Tag.ToString();
                        break;
                    }
                    break;
                }
            }
            return result;
        }
        #endregion
        #region 登录
        /// <summary>
        /// 登录按钮
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btnLogin_Click(object sender, EventArgs e)
        {
            if (logged == true)
            {
                if (MessageBox.Show("您已经登录,您需要再次进入12306网站吗?需要您已经退出,就需要重新登录!", "开源软件 温馨提示", MessageBoxButtons.YesNo, MessageBoxIcon.Information, MessageBoxDefaultButton.Button2) == DialogResult.Yes)
                {
                    this.Invoke(LoggedDelegate);
                }
                return;
            }
            if (running == false)
            {
                if (picValidImg.Image == null)
                {
                    getVerificationCode(null);
                }
                else
                {
                    if (Validate_Login() == true)
                    {
                        stop = false;
                        count = 0;
                        beginTime = DateTime.Now;
                        ThreadPool.QueueUserWorkItem(new WaitCallback(login));
                    }
                }
            }
            else
            {
                if (MessageBox.Show("目前正在尝试登录中,中止登录吗?", "开源软件 温馨提示", MessageBoxButtons.YesNo, MessageBoxIcon.Information, MessageBoxDefaultButton.Button2) == DialogResult.Yes)
                {
                    stop = true;
                }
            }
        }
        /// <summary>
        /// 登录
        /// </summary>
        /// <param name="obj"></param>
        private void login(object obj)
        {
            try
            {
                running = true;
                // 等待
                sleep();
                if (stop == true)
                {
                    return;
                }
                if (obj != null)
                {
                    Thread.CurrentThread.Name = obj.ToString();
                }
                if (logged == true)
                {
                    if (MessageBox.Show("您已经登录,您需要再次进入12306网站吗?如果您已经退出,就需要重新登录!", "开源软件 温馨提示", MessageBoxButtons.YesNo, MessageBoxIcon.Information, MessageBoxDefaultButton.Button2) == DialogResult.Yes)
                    {
                        this.Invoke(LoggedDelegate);
                    }
                    running = false;
                    return;
                }
                count++;
                System.Net.ServicePointManager.CertificatePolicy = new MyPolicy();
                //通过此路径取得登录需要的loginRand变量的值,随机码.
                string uri = "https://dynamic.12306.cn/otsweb/loginAction.do?method=loginAysnSuggest";
                string randStr = CommUitl.getString(uri, CommData.cookieContainer);
                randStr = randStr.Split(',')[0].Split(':')[1].Replace("\"", string.Empty);
                //登录请求提交路径
                uri = "https://dynamic.12306.cn/otsweb/loginAction.do?method=login";

                // 为参数变量赋值
                List<KeyValuePair<string, string>> param = new List<KeyValuePair<string, string>>();
                // 随机码
                param.Add(new KeyValuePair<string, string>("loginRand", randStr));
                // 退票登录
                param.Add(new KeyValuePair<string, string>("refundLogin", "N"));
                // 退票标识
                param.Add(new KeyValuePair<string, string>("refundFlag", "Y"));
                // 登录用户名
                param.Add(new KeyValuePair<string, string>("loginUser.user_name", txtUserName.Text));
                param.Add(new KeyValuePair<string, string>("nameErrorFocus", string.Empty));
                // 密码
                param.Add(new KeyValuePair<string, string>("user.password", txtPassword.Text));
                param.Add(new KeyValuePair<string, string>("passwordErrorFocus", string.Empty));
                // 验证码
                param.Add(new KeyValuePair<string, string>("randCode", txtVerificationCode.Text));
                param.Add(new KeyValuePair<string, string>("randErrorFocus", string.Empty));
                HttpWebResponse response = null;
                try
                {
                    // 提交登录请求
                    response = HttpWebResponseUtility.CreatePostHttpResponse(uri, param, null, DefaultUserAgent, Encoding.ASCII, CommData.cookieCollection, uri);
                }
                catch (Exception ex)
                {
                    // 显示异常信息
                    this.Invoke(this.showMsgDelegate, ex.Message);
                }

                if (response != null)
                {
                    // 得到返回的数据流
                    Stream receiveStream = response.GetResponseStream();
                    // 如果有压缩,则进行解压
                    if (response.ContentEncoding.ToLower().Contains("gzip"))
                    {
                        receiveStream = new GZipStream(receiveStream, CompressionMode.Decompress);
                    }
                    // 得到返回的字符串
                    html = new StreamReader(receiveStream).ReadToEnd();
                    // 进行各种错误判断
                    if (html.IndexOf("当前访问用户过多") > 0)
                    {
                        this.Invoke(this.showMsgDelegate, "当前访问用户过多");
                        login(null);
                    }
                    else if (html.IndexOf("请输入正确的验证码") > 0)
                    {
                        this.Invoke(focusDelegate, new object[] { txtVerificationCode });
                        this.Invoke(setControlTextDelegate, new object[] { txtVerificationCode, string.Empty, true });
                        getVerificationCode(null);
                        login(null);
                    }
                    else if (html.IndexOf("登录名不存在") > 0)
                    {
                        messageBoxShowInfo("登录名不存在!!");
                        this.Invoke(focusDelegate, new object[] { txtUserName });
                    }
                    else if (html.IndexOf("密码输入错误") > 0)
                    {
                        messageBoxShowInfo("密码输入错误,如果多次输入错误可能会被锁定帐户!");
                        this.Invoke(focusDelegate, new object[] { txtPassword });
                        this.Invoke(setControlTextDelegate, new object[] { txtPassword, string.Empty, true });
                    }
                    else if (html.IndexOf("已经被锁定") > 0)
                    {
                        messageBoxShowInfo("您的用户已经被锁定,请稍候再试!");
                    }
                    else if (html.IndexOf("系统维护中") > 0)
                    {
                        this.Invoke(this.showMsgDelegate, "系统维护中!");
                        Thread.Sleep(5000);
                        login(null);
                    }
                    else if (html.IndexOf("我的12306") > 0)
                    {
                        // 登录成功,激活窗口,提醒用户
                        this.Invoke(activateDelegate);
                        // 记录登录用时及次数
                        endTime = DateTime.Now;
                        logged = true;
                        timeSpan = endTime.Subtract(beginTime);
                        timeSpanStr = getTimeSpanString(timeSpan);

                        this.Invoke(this.showMsgDelegate, "登录成功");
                        // 触发登录成功事件
                        //this.Invoke(LoggedDelegate);
                        this.Invoke(setControlTextDelegate, new object[] { btnLogin, "已登录", true });
                        this.Invoke(set_ControlVisibleDelegate, new object[] { picLoginIE, true });
                        this.Invoke(setControlTextDelegate, new object[] { gobLoginInfo, gobLoginInfo.Text, false });
                        Bind_Passenger(null);
                    }
                    else
                    {
                        login(null);
                    }

                    Trace.WriteLine(response.StatusCode);
                }
                else
                {
                    login(null);
                }
            }
            catch (WebException webex)
            {
                this.Invoke(this.showMsgDelegate, webex.Message);
                login(null);
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message, "异常", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
            finally
            {
                running = false;
            }
        }
        #endregion
        #region MyValidate
        /// <summary>
        /// 搜索车票时的数据验证
        /// </summary>
        /// <returns></returns>
        private bool Validate_Search()
        {
            if (cboFromStation.SelectedItem == null)
            {
                messageBoxShowInfo("请输入或选择起始站!");
                cboFromStation.Focus();
                return false;
            }
            if (cboToStation.SelectedItem == null)
            {
                messageBoxShowInfo("请输入或选择终点站!");
                cboToStation.Focus();
                return false;
            }
            return true;
        }
        /// <summary>
        /// 登录验证数据
        /// </summary>
        /// <returns></returns>
        private bool Validate_Login()
        {
            if (string.IsNullOrEmpty(txtUserName.Text))
            {
                messageBoxShowInfo("请输入登录名!");
                txtUserName.Focus();
                return false;
            }
            if (string.IsNullOrEmpty(txtPassword.Text))
            {
                messageBoxShowInfo("请输入密码!");
                txtPassword.Focus();
                return false;
            }
            if (string.IsNullOrEmpty(txtVerificationCode.Text.Trim()))
            {
                messageBoxShowInfo("请输入验证码!");
                txtVerificationCode.Focus();
                return false;
            }
            return true;
        }
        private bool Validate_Refresh()
        {
            if (selectTickList.Count < 1)
            {
                messageBoxShowInfo("请“查询”您要的车票，并勾选需要刷票的车次!");
                lsbSelectedTicket.Focus();
                return false;
            }
            if (_SelectedList_SeatType.Count < 1)
            {
                messageBoxShowInfo("请勾选您接受的座位类型!");
                chbListSeatType.Focus();
                return false;
            }
            if (_SelectedList_Passengers.Count < 1)
            {
                messageBoxShowInfo("预先勾选好乘客!");
                chbListPassenger.Focus();
                return false;
            }
            return true;
        }
        #endregion

        private bool IsLogined()
        {
            if (!logged)
            {
                picLoginIE.Visible = false;
                this.Invoke(setControlTextDelegate, new object[] { btnLogin, "登录", true });
                this.Invoke(setControlTextDelegate, new object[] { gobLoginInfo, gobLoginInfo.Text, true });
                this.Invoke(set_ControlVisibleDelegate, new object[] { picLoginIE, false });
                MessageBox.Show("请输入登录信息后点“登录”按钮进行登录。", "您尚未登录", MessageBoxButtons.OK, MessageBoxIcon.Information);
                return false;
            }
            return true;
        }
        /// <summary>
        /// 查询
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btnSearch_Click(object sender, EventArgs e)
        {
            if (!IsLogined())
            {
                return;
            }
            if (!Validate_Search())
            {
                return;
            }
            this.Invoke(setControlTextDelegate, new object[] { btnSearch, "查询中", false });
            this.Invoke(setControlTextDelegate, new object[] { gobSearch, gobSearch.Text, false });
            _NeedPrePaint = true;
            BindingList<TicketInfo> list = DoSearch();
            if (list == null)
            {
                this.Invoke(setControlTextDelegate, new object[] { gobSearch, gobSearch.Text, true });
                this.Invoke(setControlTextDelegate, new object[] { btnSearch, "查询", true });
                return;
            }
            dgvTiketInfo.DataSource = list;
            if (list.Count < 1)
            {
                MessageBox.Show("不好！【" + dateStartDate.Value.ToShortDateString() + "】没车了，换个日期试试。");
            }
            this.Invoke(setControlTextDelegate, new object[] { gobSearch, gobSearch.Text, true });
            this.Invoke(setControlTextDelegate, new object[] { btnSearch, "查询", true });
        }

        private BindingList<TicketInfo> DoSearch()
        {
            try
            {
                return Ticket_Query.Query(QueryTicketParam);
            }
            catch (Exception ex)
            {
                if (ex.Message.Contains("登录"))
                {
                    showInfo("您已掉线，请登录。");
                    logged = false;
                    this.Invoke(setControlTextDelegate, new object[] { btnLogin, "登录", true });
                    this.Invoke(setControlTextDelegate, new object[] { gobLoginInfo, gobLoginInfo.Text, true });
                }
                else if (ex.Message.Contains("服务器忙") || ex.Message.Contains("超时") || ex.Message.Contains("timed out"))
                {
                    showInfo(ex.Message);
                    DoSearch();
                }
                else
                {
                    showInfo(ex.Message);
                }
            }
            return null;
        }
        
        /// <summary>
        /// 刷票按钮
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btnRefresh_Click(object sender, EventArgs e)
        {
            if (!IsLogined())
            {
                return;
            }
            if (!Validate_Refresh())
            {
                return;
            }
            this.Invoke(setControlTextDelegate, new object[] { gobSearch, gobSearch.Text, false });
            if (running == false)
            {
                stop = false;
                count = 0;
                beginTime = DateTime.Now;
                gobSelectedTicket.Enabled = false;
                gobSeatType.Enabled = false;
                btnRefresh.Text = "停止";
                chbAutoOrder.Enabled = false;
                dgvTiketInfo.DataSource = new BindingList<TicketInfo>();
                ThreadPool.QueueUserWorkItem(new WaitCallback(DoRefresh));
            }
            else
            {
                stop = true;
                running = false;
                gobSelectedTicket.Enabled = true;
                gobSeatType.Enabled = true;
                chbAutoOrder.Enabled = true;
                this.Invoke(setControlTextDelegate, new object[] { gobSearch, gobSearch.Text, true });
                this.Invoke(setControlTextDelegate, new object[] { btnRefresh, "刷票", true });
                this.Invoke(this.showMsgDelegate, "刷票停止。");
            }
        }


        private void DoRefresh(object obj)
        {
            if (Thread.CurrentThread.ApartmentState != ApartmentState.STA)
            {
                Thread.CurrentThread.ApartmentState = ApartmentState.STA;
            }
            running = true;
            count++;
            sleep();
            if (stop == true)
            {
                return;
            }
            BindingList<TicketInfo> list = null;
            list = DoSearch();
            List<TicketInfo> temp = new List<TicketInfo>();
            foreach (TicketInfo t in list)
            {
                if (t != null && t.IsAvailable_Seat(_SelectedList_SeatType.ToArray()) == true)
                {
                    foreach (TicketInfo item in selectTickList)
                    {
                        if (item.Equals(t))
                        {
                            stop = true;
                            temp.Add(t);
                        }
                    }
                }
            }
            if (temp.Count > 0)
            {
                _NeedPrePaint = true;
                dgvTiketInfo.DataSource = temp;
                this.Invoke(this.showMsgDelegate, "刷到票了！");
                dgvTiketInfo.DataSource = temp;
                gobSeatType.Enabled = true;
                gobSearch.Enabled = true;
                gobRefresh.Enabled = true;
                btnRefresh.Enabled = true;
                chbAutoOrder.Enabled = true;
                btnRefresh.Text = "刷票";
                gobSelectedTicket.Enabled = true;
                running = false;
                this.Refresh();
                if (chbAutoOrder.Checked)
                {
                    Form_Order_Add f = new Form_Order_Add(temp[0], true);
                    f.ShowDialog();
                }
                if (chbMusic.Checked)
                {
                    if (File.Exists(Application.StartupPath + @"\春运- 伤不起.mp3"))
                    {
                        Process.Start(Application.StartupPath + @"\春运- 伤不起.mp3");
                    }
                }
                return;
            }
            this.Invoke(this.showMsgDelegate, "刷新了一次，无票。");
            DoRefresh(obj);
        }

        private void Form_Main_FormClosing(object sender, FormClosingEventArgs e)
        {
            Dispose(true);
        }

        private void lsbSelectedTicket_DoubleClick(object sender, EventArgs e)
        {
            if (lsbSelectedTicket.SelectedItem == null)
            {
                return;
            }
            TicketInfo t = (lsbSelectedTicket.SelectedItem as ComboBoxItem).Value as TicketInfo;
            if (t == null)
            {
                return;
            }
            selectTickList.Remove(t);
            _NeedPrePaint = true;
            dgvTiketInfo.Refresh();
            Bind_SelectedTicket();
        }

        private void dgvTiketInfo_CellContentClick(object sender, DataGridViewCellEventArgs e)
        {
            if (e.ColumnIndex == 0)
            {
                if (selectTickList.Count < 20)
                {
                    lsbSelectedTicket.Focus();
                }
            }
        }
    }

    /// <summary>
    /// 处理证书提示
    /// </summary>
    public class MyPolicy : ICertificatePolicy
    {
        public bool CheckValidationResult(ServicePoint srvPoint,
          X509Certificate certificate, WebRequest request,
          int certificateProblem)
        {
            //Return True to force the certificate to be accepted.
            return true;
        }
    }
}
